﻿namespace Knownet.Utils
{
  using System;
  using System.IO;
  using System.Text;
  using System.Collections;

  /// <summary>
  /// 标记可回溯的文本阅读器。
  /// </summary>
  public abstract class MarkingTextReader : TextReader
  {
    #region Statics
    /// <summary>
    /// 缺省的Tab大小。
    /// </summary>
    public static int DefaultTabCount = 4;
    #endregion
    #region Fields
    /// <summary>
    /// 阅读器对应流的当前位置。
    /// </summary>
    protected long position = 0;
    /// <summary>
    /// 阅读器的当前文本（字符）位置。
    /// </summary>
    protected Location location = Location.CreateInstance();
    /// <summary>
    /// 寻址堆栈，记录阅读器对应流的
    /// 当前位置。
    /// </summary>
    protected Stack seekingStack = new Stack();
    /// <summary>
    /// 位置堆栈，记录阅读器的文本（字符）位置。
    /// </summary>
    protected Stack locationStack = new Stack();
    /// <summary>
    /// Tab对应的字符数。
    /// </summary>
    protected int tabCount = DefaultTabCount;
    #endregion
    #region Properties
    /// <summary>
    /// 获取当前阅读器记录的标记数量。
    /// </summary>
    public virtual int MarksCount
    {
      get
      {
        return this.seekingStack.Count;
      }
    }
    /// <summary>
    /// 获取或者设置当前阅读器在对应流中的位置。
    /// </summary>
    public virtual long Position
    {
      get
      {
        return this.position;
      }
      set
      {

      }
    }
    /// <summary>
    /// 获取当前阅读器的文本位置。
    /// </summary>
    public virtual Location Location
    {
      get
      {
        return this.location;
      }
    }
    /// <summary>
    /// 获取或者设置当前阅读器设定Tab的大小。
    /// </summary>
    public virtual int TabCount
    {
      get
      {
        return this.tabCount;
      }
      set
      {
        this.tabCount = (value > 0) ? value : DefaultTabCount;
      }
    }
    /// <summary>
    /// 判断当前阅读器是否可读。
    /// </summary>
    public abstract bool CanRead { get; }
    /// <summary>
    /// 判断当前阅读器是否已经被处置。
    /// </summary>
    public abstract bool IsDisposed { get; }
    #endregion
    #region Constructors
    /// <summary>
    /// 创建可标记文本阅读器。
    /// </summary>
    public MarkingTextReader()
      : this(DefaultTabCount)
    {

    }
    /// <summary>
    /// 创建可标记文本阅读器。
    /// </summary>
    public MarkingTextReader(int tabCount)
    {
      this.tabCount = (tabCount > 0) ? tabCount : 1;
    }
    #endregion
    #region Methods
    /// <summary>
    /// 重置阅读器。
    /// </summary>
    public virtual void Reset()
    {
      this.locationStack.Clear();
      this.seekingStack.Clear();
      this.position = 0L;

    }
    /// <summary>
    /// 预取下一个字符。
    /// </summary>
    /// <returns>下一个字符。</returns>
    public virtual char Peekchar()
    {
      return (char)this.Peek();
    }
    /// <summary>
    /// 读取当前字符。
    /// </summary>
    /// <returns>当前字符。</returns>
    public virtual char Readchar()
    {
      return (char)this.Read();
    }
    /// <summary>
    /// 阅读指定长度的文本。
    /// </summary>
    /// <param name="length"></param>
    /// <returns></returns>
    public abstract string ReadText(ref int length);
    /// <summary>
    /// 跳过当前字符。
    /// </summary>
    /// <returns>当前字符。</returns>
    public virtual char SkipChar()
    {
      return this.Readchar();
    }
    /// <summary>
    /// 复制当前阅读器。
    /// </summary>
    /// <returns>当前阅读器的复本。</returns>
    public virtual MarkingTextReader Duplicate()
    {
      return null;
    }
    /// <summary>
    /// 记录阅读器当前位置。
    /// </summary>
    /// <returns>栈顶元素的下标。假定堆栈在顶端压栈。</returns>
    public virtual int Mark()
    {
      try
      {
        this.seekingStack.Push(this.position);
        this.locationStack.Push(this.location.Duplicate());
        return this.seekingStack.Count - 1;

      }
      catch (InvalidOperationException)
      {

      }
      return int.MinValue;
    }
    /// <summary>
    /// 恢复到最后记录的位置。
    /// </summary>
    /// <returns>
    /// 栈顶元素的下标。假定堆栈在顶端压栈。
    /// 如果出现错误，返回int.MinValue。
    /// </returns>
    public virtual int Recall()
    {
      try
      {
        this.position = (long)this.seekingStack.Pop();
        this.location = (Location)this.locationStack.Pop();

        return this.MarksCount - 1;
      }
      catch (InvalidCastException)
      {

      }
      return int.MinValue;
    }
    /// <summary>
    /// 舍弃当前栈顶。
    /// </summary>
    /// <returns>
    /// 栈顶元素的下标。假定堆栈在顶端压栈。
    /// 如果出现错误，返回int.MinValue。
    /// </returns>
    public virtual int Discard()
    {
      try
      {
        this.seekingStack.Pop();
        this.locationStack.Pop();

        return this.MarksCount - 1;
      }
      catch (InvalidOperationException)
      {

      }
      return int.MinValue;
    }
    /// <summary>
    /// 重定位字符，用于同步位置信息。
    /// </summary>
    /// <remarks>
    /// 实现char[]和string两个版本是出于效率的考虑。
    /// </remarks>
    protected virtual void Relocate(string chars)
    {
      if (chars != null)
      {
        int length = chars.Length;
        for (int i = 0; i < length; i++)
        {
          if (chars[i] == '\r')
          {
            if ((i + 1) < length && chars[i + 1] == '\n')
            {
              i++;
            }
            this.location.IncreaseRow();
          }
          else if (chars[i] == '\n')
          {
            this.location.IncreaseRow();
          }
          else
          {
            this.location.IncreaseChar(chars[i] == '\t' ? this.tabCount : 1);
          }
        }
      }
    }
    /// <summary>
    /// 重定位字符，用于同步位置信息。
    /// </summary>
    /// <remarks>
    /// 实现char[]和string两个版本是出于效率的考虑。
    /// </remarks>
    protected virtual void Relocate(char[] chars)
    {
      if (chars != null)
      {
        int length = chars.Length;
        for (int i = 0; i < length; i++)
        {
          if (chars[i] == '\r')
          {
            if ((i + 1) < length && chars[i + 1] == '\n')
            {
              i++;
            }
            this.location.IncreaseRow();
          }
          else if (chars[i] == '\n')
          {
            this.location.IncreaseRow();
          }
          else
          {
            this.location.IncreaseChar(chars[i] == '\t' ? this.tabCount : 1);
          }
        }
      }
    }
    #endregion
  }
}
